﻿using Century.EnterpriseLibrary.Caching;
using Century.EnterpriseLibrary.Configuration;
using Century.Model;
using Century.Model.CMS;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Century.Business.CMS
{
    public class SiteService : BSOBase<Site, CenturyDbContext>, ISiteService
    {
        #region [ Private Method(s) ]
        private SitePage GetSiteHomePage(int siteId)
        {
            using (Context = new CenturyDbContext())
            {
                SitePage page = Context.SitePages.Include("PageLayout").FirstOrDefault(c => c.IsHomePage && c.SiteId == siteId);
                if (page == null)
                {
                    page = Context.SitePages.Include("PageLayout").FirstOrDefault(c => c.SiteId == siteId);
                    if (page == null)
                    {
                        page = Context.SitePages.Include("PageLayout").FirstOrDefault(c => c.IsHomePage);

                    }
                }
                List<SitePage> sitePages = GetSitePages(page.SiteId);
                SitePage pageInList = sitePages.FirstOrDefault(c => c.Id == page.Id);
                sitePages.Remove(pageInList);
                sitePages.Add(page);
                return page;
            }
        }

        SitePage GetSitePage(string pageName, int siteId)
        {
            using (Context = new CenturyDbContext())
            {
                SitePage page = Context.SitePages.Include("PageLayout").FirstOrDefault(c => c.SiteId == siteId && c.LocalName == pageName);
                List<SitePage> sitePages = GetSitePages(page.SiteId);
                SitePage pageInList = sitePages.FirstOrDefault(c => c.Id == page.Id);
                sitePages.Remove(pageInList);
                sitePages.Add(page);
                return page;
            }
        }

        private ContentHolder GetSiteContentHolder(string holderName, int siteId, string pageName)
        {
            using (Context = new CenturyDbContext())
            {
                SitePage page = GetPage(pageName, siteId);

                ContentHolder result = Context.ContentHolders.Include("ContentHolderParts.StaticContent").Include("ContentHolderParts.DynamicContent").FirstOrDefault(c => c.Name == holderName && c.PageLayoutId == page.PageLayoutId);
                List<ContentHolderPart> deleteList = new List<ContentHolderPart>();
                foreach (var item in result.ContentHolderParts)
                {
                    if (item.SitePageId != page.Id)
                    {
                        deleteList.Add(item);
                    }
                }
                foreach (var item in deleteList)
                {
                    result.ContentHolderParts.Remove(item);
                }
                return result;
            }

        }

        private List<PageLayout> GetPageLayoutsFromDB()
        {
            using (Context = new CenturyDbContext())
            {
                return Context.PageLayouts.ToList();
            }
        }

        private List<SitePage> GetSitePagesFromDB(int siteId)
        {
            using (Context = new CenturyDbContext())
            {
                return Context.SitePages.Include("PageLayout").Where(c => c.SiteId == siteId).OrderBy(c=>c.NodeOrder).ToList();
            }
        }

        private List<DynamicContent> GetDynamicContentsFromDB()
        {
            using (Context = new CenturyDbContext())
            {
                return Context.DynamicContents.ToList();
            }
        }

        #endregion

        public Model.CMS.SitePage GetPage(string pageName, int siteId)
        {
            //TODO: Get a list of page names and local page names to map them on cache and search by page name or local page name

            if (!string.IsNullOrEmpty(pageName))
            {
                return CacheService.Get<SitePage>(string.Format("st_pg_{0}_{1}", pageName, siteId), () => GetSitePage(pageName, siteId), ConfManager.Instance.CacheManager.CacheExTime);
            }
            else
            {
                return CacheService.Get<SitePage>(string.Format("st_pg_hmpg_{0}", siteId), () => GetSiteHomePage(siteId), ConfManager.Instance.CacheManager.CacheExTime);
            }

        }

        public Site GetSiteByPath(string stPath)
        {
            return CacheService.Get<Site>(string.Format("st_{0}", stPath), () => Find(c => c.Path.ToLower() == stPath.ToLower()), ConfManager.Instance.CacheManager.CacheExTime);
        }

        public ContentHolder GetContentHolder(string holderName, int siteId, string pageName)
        {
            return CacheService.Get<ContentHolder>(string.Format("st_ch_{0}_{1}_{2}", holderName, pageName, siteId), () => GetSiteContentHolder(holderName, siteId, pageName), ConfManager.Instance.CacheManager.CacheExTime);
        }

        public SitePage GetPage(int pageID)
        {
            using (Context = new CenturyDbContext())
            {
                return Context.SitePages.FirstOrDefault(c => c.Id == pageID);
            }
        }

        public List<SitePage> GetSitePages(int siteId)
        {
            return CacheService.Get<List<SitePage>>(string.Format("st_Pg_lst_{0}", siteId), () => GetSitePagesFromDB(siteId), ConfManager.Instance.CacheManager.CacheExTime);
        }

        public List<Site> GetSites()
        {
            using (Context = new CenturyDbContext())
            {
                return GetAll().ToList();
            }
        }

        public List<PageLayout> GetPageLayouts()
        {
            return CacheService.Get<List<PageLayout>>("st_pLayouts", () => GetPageLayoutsFromDB(), ConfManager.Instance.CacheManager.CacheExTime);
        }
        private static readonly object updatePageLocker = new object();

        public void UpdatePage(SitePage page)
        {
            using (Context = new CenturyDbContext())
            {
                Context.SitePages.Attach(page);
                Context.Entry(page).State = System.Data.Entity.EntityState.Modified;
                Context.SaveChanges();
                if (page.IsHomePage)
                {
                    CacheService.Remove(string.Format("st_pg_hmpg_{0}", page.SiteId));
                }
                CacheService.Remove(string.Format("st_pg_{0}_{1}", page.Name, page.SiteId));
                lock (updatePageLocker)
                {
                    List<SitePage> pageList = GetSitePages(page.SiteId);
                    SitePage oldPage = pageList.FirstOrDefault(c => c.Id == page.Id);
                    if (oldPage != null)
                    {
                        pageList.Remove(oldPage);
                        pageList.Add(page);
                    }
                    else
                    {
                        pageList.Add(page);
                    }
                    CacheService.Add(string.Format("st_Pg_lst_{0}", page.SiteId), pageList, ConfManager.Instance.CacheManager.CacheExTime);
                }
            }
        }

        private static readonly object addPageLocker = new object();

        public void AddNewPage(SitePage sitePage)
        {
            using (Context = new CenturyDbContext())
            {
                Context.SitePages.Add(sitePage);
                Context.SaveChanges();

                lock (addPageLocker)
                {
                    sitePage = Context.SitePages.Include("PageLayout").FirstOrDefault(c => c.Id == sitePage.Id);
                    if (CacheService.Get<SitePage>(string.Format("st_pg_{0}_{1}", sitePage.Name, sitePage.SiteId)) == null && CacheService.Get<SitePage>(string.Format("st_pg_hmpg_{0}", sitePage.SiteId)) == null)
                    {
                        if (!sitePage.IsHomePage)
                        {
                            CacheService.Add(string.Format("st_pg_{0}_{1}", sitePage.Name, sitePage.SiteId), sitePage, ConfManager.Instance.CacheManager.CacheExTime);
                        }
                        else
                        {
                            CacheService.Add(string.Format("st_pg_hmpg_{0}", sitePage.SiteId), sitePage, ConfManager.Instance.CacheManager.CacheExTime);
                        }
                    }

                    List<SitePage> pageList = GetSitePages(sitePage.SiteId);
                    if (!pageList.Any(c => c.Id == sitePage.Id))
                    {
                        pageList.Add(sitePage);
                        CacheService.Add(string.Format("st_Pg_lst_{0}", sitePage.SiteId), pageList, ConfManager.Instance.CacheManager.CacheExTime);
                    }
                }
            }

        }

        public List<DynamicContent> GetDynamicContents()
        {
            return CacheService.Get<List<DynamicContent>>("dn_cnt", () => GetDynamicContentsFromDB(), ConfManager.Instance.CacheManager.CacheExTime);
        }

        public Site GetDefaulSite()
        {
            using (Context = new CenturyDbContext())
            {
                return Context.Sites.FirstOrDefault(c => c.IsDefault);
            }
        }

        public void AddNewSite(Site site)
        {
            using (Context = new CenturyDbContext())
            {
                Context.Sites.Add(site);
                Context.SaveChanges();
            }
        }


        public ContentHolderPart AddStaticContent(int pageId, int holderId)
        {
            using (Context = new CenturyDbContext())
            {
                StaticContent staticContent = new StaticContent { Description = "Double click to edit." };
                ContentHolderPart contentPart = new ContentHolderPart
                {
                    ContentHolderId = holderId,
                    SitePageId = pageId,
                    PartOrder = 1,
                    StaticContent = staticContent
                };
                Context.ContentHolderParts.Add(contentPart);
                Context.SaveChanges();
                // Context.SitePages.First().ContentHolderParts
                ContentHolderPart resultContentPart = Context.ContentHolderParts.Include("SitePage").Include("ContentHolder").Include("StaticContent").First(c => c.Id == contentPart.Id);
                CacheService.Add(string.Format("st_ch_{0}_{1}_{2}", resultContentPart.ContentHolder.Name,
                    resultContentPart.SitePage.Name, resultContentPart.SitePage.SiteId),
                    GetSiteContentHolder(resultContentPart.ContentHolder.Name, resultContentPart.SitePage.SiteId, resultContentPart.SitePage.Name), ConfManager.Instance.CacheManager.CacheExTime);
                return resultContentPart;
            }
        }


        public bool RemovePart(int pageId, int partId)
        {
            using (Context = new CenturyDbContext())
            {
                ContentHolderPart resultContentPart = Context.ContentHolderParts.Include("SitePage").Include("ContentHolder").Include("StaticContent").FirstOrDefault(c => c.Id == partId && c.SitePageId == pageId);
                if (resultContentPart != null)
                {
                    string pageName = resultContentPart.SitePage.Name;
                    string holderName = resultContentPart.ContentHolder.Name;
                    int siteId = resultContentPart.SitePage.SiteId;
                    Context.ContentHolderParts.Remove(resultContentPart);
                    bool flag = Context.SaveChanges() > 0;
                    if (flag)
                    {
                        CacheService.Remove(string.Format("st_ch_{0}_{1}_{2}", holderName, pageName, siteId));

                    }
                    return flag;
                }
                else
                {
                    return false;
                }
            }

        }


        public void UpdateStaticContent(int staticContentId, string value, int pageId)
        {
            using (Context = new CenturyDbContext())
            {
                StaticContent staticContent = Context.StaticContents.Include("ContentHolderParts.ContentHolder").FirstOrDefault(c => c.Id == staticContentId);
                if (staticContent != null)
                {
                    staticContent.Description = value;
                    if (Context.SaveChanges() > 0)
                    {
                        SitePage sitePage = Context.SitePages.FirstOrDefault(c => c.Id == pageId);
                        if (sitePage != null)
                        {
                            CacheService.Remove(string.Format("st_ch_{0}_{1}_{2}", staticContent.ContentHolderParts.First().ContentHolder.Name, sitePage.Name, sitePage.SiteId));
                        }
                    }
                }
            }
        }


        public void DeletePage(int pageId)
        {
            using (Context = new CenturyDbContext())
            {

                lock (addPageLocker)
                {
                    SitePage page = Context.SitePages.FirstOrDefault(c => c.Id == pageId);
                    if (page != null)
                    {
                        Context.SitePages.Remove(page);
                        CacheService.Remove(string.Format("st_pg_{0}_{1}", page.Name, page.SiteId));
                        CacheService.Remove(string.Format("st_pg_hmpg_{0}", page.SiteId));
                        List<SitePage> pageList = GetSitePages(page.SiteId);
                        if (pageList.Any(c => c.Id == pageId))
                        {
                            SitePage pg = pageList.First(p => p.Id == pageId);
                            pageList.Remove(pg);
                            CacheService.Add(string.Format("st_Pg_lst_{0}", page.SiteId), pageList, ConfManager.Instance.CacheManager.CacheExTime);
                        }
                        Context.SaveChanges();
                    }
                }

            }
        }


        public List<SitePage> GetSubPages(int pageId, int siteId)
        {
            List<SitePage> sitePages = GetSitePages(siteId);
            return sitePages.Where(c => c.ParentId == pageId).OrderBy(c=>c.NodeOrder).ToList();
        }
    }
}
